#include "TreeTest.h"
#include "tree/TreeIterator.h"

namespace etu {

using etu::tree::TreeIterator;

void TreeTest::setUp() {
    this->tree = new Tree<int>();
}

void TreeTest::tearDown() {
    delete this->tree;
}

void TreeTest::sizeTest() {
    CPPUNIT_ASSERT_EQUAL(0, this->tree->getSize());

    this->tree->setRoot(1);
    CPPUNIT_ASSERT_EQUAL(1, this->tree->getSize());

    this->tree->addChild(1, 2);
    CPPUNIT_ASSERT_EQUAL(2, this->tree->getSize());

    this->tree->addChild(2, 3);
    CPPUNIT_ASSERT_EQUAL(3, this->tree->getSize());

    this->tree->addParent(2, 4);
    CPPUNIT_ASSERT_EQUAL(4, this->tree->getSize());

    this->tree->addParent(3, 5);
    CPPUNIT_ASSERT_EQUAL(5, this->tree->getSize());
}

void TreeTest::rootTest() {
    this->tree->setRoot(1);
    CPPUNIT_ASSERT_EQUAL(1, this->tree->getRoot());
    
    this->tree->setRoot(2);
    CPPUNIT_ASSERT_EQUAL(2, this->tree->getRoot());
}

void TreeTest::emptynessTest() {
    CPPUNIT_ASSERT_EQUAL(true, this->tree->isEmpty());
    this->tree->setRoot(1);
    CPPUNIT_ASSERT_EQUAL(false, this->tree->isEmpty());
}

void TreeTest::childsTest() {
    this->tree->setRoot(1);
    this->tree->addChild(1, 2);
    this->tree->addChild(2, 3);

    CPPUNIT_ASSERT_EQUAL(true, this->tree->isChild(2, 1));
    CPPUNIT_ASSERT_EQUAL(true, this->tree->isChild(3, 2));

    std::list<int>* rootChilds = this->tree->getChilds(1);
    CPPUNIT_ASSERT_EQUAL(1, (int) rootChilds->size());
    CPPUNIT_ASSERT_EQUAL(2, rootChilds->back());

    std::list<int>* nodeChilds = this->tree->getChilds(2);
    CPPUNIT_ASSERT_EQUAL(1, (int) nodeChilds->size());
    CPPUNIT_ASSERT_EQUAL(3, nodeChilds->back());

    delete rootChilds;
    delete nodeChilds;
}

void TreeTest::contentTest() {
    this->tree->setRoot(1);
    this->tree->addChild(1, 2);
    this->tree->addChild(2, 3);

    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(1));
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(2));
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(3));
    CPPUNIT_ASSERT_EQUAL(false, this->tree->contains(4));
}

void TreeTest::iteratorTest() {
    std::list<int> items;

    for(int i = 1; i <= 10; i++) {
        items.push_back(i);
    }

    this->tree->setRoot(1);
    this->tree->addChild(1, 2);
    this->tree->addChild(2, 3);
    this->tree->addChild(3, 5);
    this->tree->addChild(3, 6);
    this->tree->addParent(3, 4);
    this->tree->addChild(6, 7);
    this->tree->addChild(6, 8);
    this->tree->addParent(6, 9);
    this->tree->addChild(4, 10);
    this->tree->addParent(10, 2);

    TreeIterator<int>* it = this->tree->getIterator();
    int value;

    while(it->hasNext()) {
        value = it->next();
        items.remove(value);
    }

    delete it;

    CPPUNIT_ASSERT_EQUAL(0, (int) items.size());
}

void TreeTest::parentTest() {
    this->tree->setRoot(1);
    this->tree->addChild(1, 2);
    this->tree->addChild(2, 3);

    std::list<int>* parents = this->tree->getParents(2);

    CPPUNIT_ASSERT_EQUAL(1, (int) parents->size());
    CPPUNIT_ASSERT_EQUAL(1, parents->back());

    delete parents;

    parents = this->tree->getParents(3);
    
    CPPUNIT_ASSERT_EQUAL(1, (int) parents->size());
    CPPUNIT_ASSERT_EQUAL(2, parents->back());

    delete parents;
}

void TreeTest::addTest() {
    CPPUNIT_ASSERT_EQUAL(0, this->tree->getSize());

    this->tree->setRoot(1);
    CPPUNIT_ASSERT_EQUAL(1, this->tree->getSize());
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(1));

    this->tree->addChild(1, 2);
    CPPUNIT_ASSERT_EQUAL(2, this->tree->getSize());
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(2));

    this->tree->addChild(2, 3);
    CPPUNIT_ASSERT_EQUAL(3, this->tree->getSize());
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(3));
}

void TreeTest::removeTest() {
    CPPUNIT_ASSERT_EQUAL(0, this->tree->getSize());

    this->tree->setRoot(1);
    CPPUNIT_ASSERT_EQUAL(1, this->tree->getSize());
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(1));

    this->tree->addChild(1, 2);
    CPPUNIT_ASSERT_EQUAL(2, this->tree->getSize());
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(2));

    this->tree->addChild(1, 3);
    CPPUNIT_ASSERT_EQUAL(3, this->tree->getSize());
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(3));

    this->tree->addChild(2, 4);
    CPPUNIT_ASSERT_EQUAL(4, this->tree->getSize());
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(4));

    this->tree->addChild(3, 4);
    CPPUNIT_ASSERT_EQUAL(4, this->tree->getSize());
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(4));

    this->tree->remove(4);
    CPPUNIT_ASSERT_EQUAL(3, this->tree->getSize());
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(1));
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(2));
    CPPUNIT_ASSERT_EQUAL(true, this->tree->contains(3));
    CPPUNIT_ASSERT_EQUAL(false, this->tree->contains(4));

    this->tree->remove(1);
    CPPUNIT_ASSERT_EQUAL(0, this->tree->getSize());
    CPPUNIT_ASSERT_EQUAL(false, this->tree->contains(1));
    CPPUNIT_ASSERT_EQUAL(true, this->tree->isEmpty());
}

void TreeTest::serializationTest() {
    Tree<int> srcTree;
    srcTree.setRoot(1);
    srcTree.addChild(1, 2);
    srcTree.addChild(2, 3);
    srcTree.addChild(3, 5);
    srcTree.addChild(3, 6);
    srcTree.addParent(3, 4);
    srcTree.addChild(6, 7);
    srcTree.addChild(6, 8);
    srcTree.addParent(6, 9);
    srcTree.addChild(4, 10);

    std::ostringstream oss;
    std::istringstream iss;

    oss << srcTree;
    iss.str(oss.str());

    Tree<int>* dstTree = new Tree<int>();
    iss >> (* dstTree);

    CPPUNIT_ASSERT_EQUAL(true, dstTree->getRoot() == srcTree.getRoot()); // TODO
}

}
